Flutter桌面端开发 您所在的位置:网站首页 pickerViewcontroller 读取文件 Flutter桌面端开发

Flutter桌面端开发

2023-09-27 22:24| 来源: 网络整理| 查看: 265

注意:查看本文章前请先查看更新日志,以至于该文章适合插件的最新版本

更新日志 详情日期 更新了插件的版本和file_selector的部分用法2023-08-13 更新了插件的版本,用法不变2022-12-10 更新了file_selector在0.8.4+3版本存储文件的用法2022-06-13 修正了file_picker存储文件的用法2022-05-24

上一节讲了怎么拖动文件到应用中,从应用中点击按钮弹出选择框上传文件,也是必不可少的一个功能。

file_selector 安装🛠

点击file_selector获取最新版本。以下是在编写本文章时的最新版本:

file_selector: ^1.0.0

👻注意:在开发 macOS 端的程序时,还需要额外的操作,具体可以查看这里

了解🧩

在 file_selector 插件中,我们需要了解对象 XTypeGroup 和方法 openFiles。

XTypeGroup的作用是使用给定的标签和文件扩展名创建一个新组,没有提供任何类型选项的组表示允许任何类型。

XTypeGroup 可以传入5个参数:

String? label:用来自己作区分 List? extensions:过滤非描述的后缀文件,默认加载全部类型的文件 List? mimeTypes:主要针对 Linux 系统下的文件类型 List? macUTIs:主要针对 mac 系统下的文件类型 List? webWildCards:主要针对网页开发时的类型

openFile 方法返回一个 XFile 对象,可以传入3个参数:

List acceptedTypeGroups = const []:接受的类型组,传入一个XTypeGroup列表 String? initialDirectory:初始化文件夹。打开文件对话框以加载文件并返回文件路径 String? confirmButtonText:弹窗“打开”按钮的显示文字

openFiles 方法返回 XFile 对象列表,传入的参数和 openFile 一样。

使用🥩

选择的文件我们最后需要读取出来,读取需要接受一个 String 类型的路径:

String path = '';

这里先以选择图片为例,我们需要先定义一个 XTypeGroup 对象:

final xType = XTypeGroup(label: '图片', extensions: ['jpg', 'png']); 选择单张图片

打开弹窗选取单个文件,使用 openFile 方法:

final XFile? file = await openFile(acceptedTypeGroups: [xType]);

将获取到的 XFile 对象的路径值传给 path。当然,并不是每次打开弹窗都会选择图片,所以需要判断一下:

if (file != null) { path = file.path; setState((){}); } else { BotToast.showText(text: '你不选择图片打开干啥😤'); }

image

openFile 方法中还有两个属性,我们修改试一下:

final XFile? file = await openFile( acceptedTypeGroups: [xType], initialDirectory: r'C:\Users\ilgnefz\Pictures', confirmButtonText: '嘿嘿嘿', );

image

initialDirectory 属性貌似没用😕去看了官方的例子,也没用到过这个参数,以后就忽略它吧。

选择多张图片

选取多张图片,我们就需要定义一个路径的数组了:

final List paths = [];

XTypeGroup 对象和刚才的一样就行,重要的是使用 openFiles 方法:

final List files = await openFiles(acceptedTypeGroups: [xType]);

将获取到的文件路径列表赋值给 paths:

if (file != null) { paths.addAll(files.map((e) => e.path).toList()); setState((){}); } else { BotToast.showText(text: '你不选择图片打开干啥😤'); }

好了,来看看效果如何

image

读取文本文件

读取文本文件,我们需要获取文件的名称和内容:

final String title = ''; final String content = '';

再更改一下 XTypeGroup 对象就行:

final XTypeGroup xType = XTypeGroup(label: '文本', extensions: ['txt']); final XFile? file = await openFile(acceptedTypeGroups: [xType]);

将获取到的 XFile 对象的属性赋值给我们定义的对象:

if (file != null) { title = file.name; content = await file.readAsString(); setState((){}); } else { BotToast.showText(text: '打开了个寂寞🙄'); }

image

存储文本文件

存储文本需要用到 XFile 对象中的 fromData 方法。让我们来看看这个方法中需要传入什么参数:

Uint8List bytes:存储的主要内容 String? mimeType:文件的 mine 类型 String? name:文件名?测试了毫无用处😑 int? length:不知道是什么的长度,反正无法截取内容😑 DateTime? lastModified:最后修改文件的时间 String? path:文件保存的路径?测试了毫无效果😑 CrossFileTestOverrides? overrides:覆盖CrossFile的某些方法用来测试

(以上几个参数要是有朋友测试出来了,可以告知一下😁)

在存储文本文件前,我们需要先知道应该存储在哪个文件夹:

final FileSaveLocation? path = await getSaveLocation();

getSaveLocation有以下几个可选参数:

List acceptedTypeGroups:可以在对话框中选择的文件类型组的列表。其显示方式取决于 pltaform,例如: 在 Windows 和 Linux 上,每个组将是过滤器选项列表中的一个条目 在 macOS 上,将允许所有组允许的所有类型的并集 String? initialDirectory:打开对话框时将显示的目录的完整路径。如果未提供,平台将选择一个初始位置 String? suggestedName:文件名的初始值 String? confirmButtonText:对话框的确认按钮中的文本。如果未提供,则使用默认操作系统标签(例如,“保存”)

以下是没传任何参数的效果:

image

以下是传了参数的效果:

final FileSaveLocation? path = await getSaveLocation( acceptedTypeGroups: [ XTypeGroup(label: '图片', extensions: ['jpg', 'png']), XTypeGroup(label: '视频', extensions: ['mp4', 'avi']) ], initialDirectory: r'C:\Users\ilgnefz\Pictures', suggestedName: '新建文件', confirmButtonText: '点我吧!', );

image

XFile.fromData 虽然有很多参数可以使用,但是大部分没有啥效果,通过上面的示例,我们可以直接使用getSaveLocation方法来是指必要的内容:

final String title = widget.provider.title; final String content = widget.provider.txtContent; final Uint8List fileData = const Utf8Encoder().convert(content); // final Uint8List fileData = Uint8List.fromList(content.codeUnits); final FileSaveLocation? saveLocation = await getSaveLocation( acceptedTypeGroups: [ const XTypeGroup(label: '文本', extensions: ['txt']), ], initialDirectory: r'C:\Users\ilgnefz\Pictures', suggestedName: title, ); debugPrint('存储路径:${saveLocation?.path}'); if (saveLocation != null) { const String fileMimeType = 'text/plain'; final XFile xFile = XFile.fromData( fileData, mimeType: fileMimeType, ); await xFile.saveTo(saveLocation.path); } else { BotToast.showText(text: '给你个眼神自己体会😑'); }

image

现在去选择的文件夹就能找到我们存储的文件了。initialDirectory是路径的初始值,我打开文本改变了路径,所以就没生效。

选择文件夹

选择文件夹使用 getDirectoryPath 方法:

final String? path = await getDirectoryPath(); if (path != null) { title = '目录'; content = path; setState((){}); }

6

选择多文件夹

选择多文件夹需要使用 getDirectoryPaths 方法:

final List paths = await getDirectoryPaths(); if (paths.isNotEmpty) { widget.provider.setTitle('多目录'); widget.provider.setTextContent(paths.join('\n')); widget.provider.setFileType('text'); }

image

file_picker 安装🛠

点击file_picker获取最新版本。以下是在编写本文章时的最新版本:

file_picker: ^5.3.3 使用🥩

先定义一个默认的路径:

String path = ''; 选择单个文件

选择单个文件需要用到 pickFiles 方法,该方法可以传入10个参数:

String? dialogTitle:弹窗的标题 String? initialDirectory:初始化的文件夹 FileType type = FileType.any:文件的类型 List? allowedExtensions:允许的文件后缀名称,需配合FileType.custom使用 dynamic Function(FilePickerStatus)? onFileLoading:监听文件选择的状态 bool allowCompression = true:是否允许压缩 bool allowMultiple = false:是否允许选择多个文件 bool withData = false:如果为true,选取的文件将在内存中立即以“Uint8List”的形式提供其字节数据,如果您选择它进行服务器上传或类似操作,这将很有用。但是,请记住,如果您允许多个选择或选择大文件,则在 IO(iOS 和 Android)上启用此功能可能会导致内存不足问题。请改用 [withReadStream]。在 web 上默认为 true,其他为 false bool withReadStream = false:拾取的文件将以 [Stream] 的形式提供其字节数据,这对于上传和处理大文件很有用 bool lockParentWindow = false:是否将子窗口(文件选择器窗口)一直停留在 Flutter 窗口的前面,直到它关闭(如模态窗口)。此参数仅适用于 Windows FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { File file = File(result.files.single.path!); path = file.path; setState((){}); }

image

我们试着添加一些参数:

FilePickerResult? result = await FilePicker.platform.pickFiles( dialogTitle: '我的地盘我做主', initialDirectory: r'C:\Users\ilgnefz\Pictures\Saved Pictures', type: FileType.image, );

8

initialDirectory 又没起作用😑

选择多个文件

定义一个接受所有路径的数组:

final List paths = []; FilePickerResult? result = await FilePicker.platform.pickFiles( allowMultiple: true, ); if (result != null) { paths = result.files.map((e) => e.path!).toList(); setState((){}); } 读取文件信息

通过以上的方法,我们会得到一个 PlatformFile 对象:

FilePickerResult? result = await FilePicker.platform.pickFiles(); PlatformFile file = result.files.single;

该对象有以下几个属性:

name:文件名称 size:文件大小,以字节为单位 bytes:此文件的字节数据。如果您想操作其数据或轻松上传到其他地方,则特别有用。 在常见问题解答中查看此处 一个关于如何使用它在网络上上传的示例。 extension:文件后缀 path:文件路径 identifier:原始文件的平台标识符,是指 Android 上的 Uri 和 iOS 上的 NSURL。其他为null readStream:将文件内容转换成流读取

1

存储文件

存储文件需要使用 saveFile 方法,该方法有可以传入6个参数:

String? dialogTitle:同 pickFiles 方法 String? fileName:存储文件的名字 String? initialDirectory:同 pickFiles 方法 FileType type = FileType.any:同 pickFiles 方法 List ? allowedExtensions:同 pickFiles 方法 bool lockParentWindow = false:同 pickFiles 方法 String? outputFile = await FilePicker.platform.saveFile(fileName: 'hello.txt');

image

这个时候我们去选择的文件夹查看,并不能发现我们存储的文件。这是因为这个方法并不能直接存储文件,我们把outputFile打印一下会发现以下结果:

outputFile: C:\Users\ilgnefz\Pictures\hello.txt

诶😀虽然它不能帮我们直接存储一个文件,但是会返回一个文件的路径。我们可以使用File对象来将需要的内容存储下来。

if (outputFile != null) { File file = File(outputFile); await file.writeAsString('Hello World'); await file.create(); BotToast.showText(text: '文件存储成功'); }

image

现在我们打开文件存储时选择的文件夹查看

image

获取文件夹路径

获取文件夹需要使用 getDirectoryPath 方法,可以传入3个参数:

String? dialogTitle:同 pickFiles 方法 bool lockParentWindow = false:同 pickFiles 方法 String? initialDirectory:同 pickFiles 方法 String title = ''; String content = ''; String? dir = await FilePicker.platform.getDirectoryPath(); if (dir != null) { title = '目录'; content = dir; setState((){}); }

9

🛫OK,以上就是这篇文章的全部内容,仅针对插件的当前版本,并不能保证适用于以后插件用法的更新迭代。

最后,感谢 flutter 团队和 miguelpruivo 对以上插件的开发和维护😁。本应用代码已上传至 github 和 gitee,有需要的可以下载下来查看学习。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有